#pragma once 
#include <iostream>
#include <string>
#include <cassert>
#include <functional>
#include "Socket.hpp"
#include "Log.hpp"
#include "Epoll.hpp"

static const int gport = 8888;
using func_t = std::function<std::string(std::string)>;


class EpollServer {
         static const int gnum = 64;
    public:
        EpollServer(func_t func, uint16_t port = gport) : func_(func), port_(port) {}
        void InitServer() {
            listensock_.Socket();
            listensock_.Bind(port_);
            listensock_.Listen();
            epoller_.Create();
        }

        void Start() {
            // 1 将listensock_添加到epoll中
            bool r = epoller_.AddEvent(listensock_.Fd(), EPOLLIN);
            assert(r);
            (void)r;

            int timeout = -1;
            while (true) {
                int n = epoller_.Wait(revs, gnum, timeout);
                switch(n) {
                    case 0 : 
                        logMessage(DEBUG, "timeout..."); break;
                    case -1: 
                        logMessage(WARRING, "epoll_wait failed"); break;
                    default: 
                        HandlerEvents(n);
                        break;
                }
                sleep(1);
            }
        }

        void HandlerEvents(int num) {
            for (int i = 0; i < num; i++) {
                int fd = revs[i].data.fd;
                uint32_t events = revs[i].events; 


                if (events & EPOLLIN) { // 读事件就绪
                    // a 新连接事件到来
                    if (fd == listensock_.Fd()) {
                        logMessage(DEBUG, "Get a new Link ...");
                        GetNewLink();
                    }
                    else {
                        logMessage(DEBUG, "%d data need read ...");
                        GetSockMessage(fd);
                    }
                    // b 数据到来
                }
            }
        }

        void GetNewLink() {
            std::string clientip;
            uint16_t clientport;
            int sock = listensock_.Accept(&clientip, &clientport);
            if (sock < 0) return;
            logMessage(DEBUG, "%s:%d 已经连上了服务器", clientip.c_str(), clientport);
            epoller_.AddEvent(sock, EPOLLIN);
        }

        void GetSockMessage(int fd) {
            char buffer[1024];
            ssize_t s = recv(fd, buffer, sizeof(buffer) - 1, 0);
            if (s > 0) {
                buffer[s] = 0;
                std::cout << "client # " << buffer << std::endl;

                // 发送回去也要被epoll管理
                std::string response = func_(buffer);
                send(fd, response.c_str(), response.size(), 0);
            }
            else {
                if (s == 0) 
                    logMessage(DEBUG, "client quit ...");
                else 
                    logMessage(WARRING, "recv error, client quit ...");
                // 处理异常时，需要先进行移除，再关闭文件描述符
                epoller_.DelEvent(fd);
                close(fd);
            }
        }

        ~EpollServer() {
            listensock_.Close();
            epoller_.Close();
        }

    private:
        uint16_t port_;
        Sock listensock_;
        Epoller epoller_;
        struct epoll_event revs[gnum];
        func_t func_;
};